package com.sff.module {
	
	import com.sff.core.sff_internal;
	import com.sff.events.ModuleEvent;
	
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;	

	public class ModuleLoaderFactory extends EventDispatcher {

		//current modules of factory
		protected var _module 	: Module;
		
		//store array of module loader item
		protected var _loaders 	: Array;
		
		//store array of module object class
		protected var _modules 	: Array;
		
		public function ModuleLoaderFactory( module : Module ) {
			_module = module;
			
			_loaders = new Array();
			_modules = new Array( );
		}
		
		public function contains( module : Module ) : Boolean {
			return _modules.indexOf( module ) > -1;
		}
		
		public function get modules() : Array {
			return _modules;
		}
		
		public function get loaders() : Array {
			return _loaders;
		}
		
		public function removeModule(child : Module) : void {
			unregisterModule( child );
			
			var index:int = _modules.indexOf(child);			
			if (index != -1) {
				_modules.splice(index, 1);
			}
		}

		public function getModuleLoader() : ModuleLoader {
			
			var ldr : ModuleLoader = new ModuleLoader(_module );
			
			_loaders.push(ldr);
			registerLoader(ldr);
			
			return ldr;
		}
		
		public function dispose() : void {
			
			//remove all module loaders
			for each (var ldr : ModuleLoader in _loaders) {
				unregisterLoader(ldr);
				
				ldr.dispose();
				ldr = null;
			}

			//remove all loaded modules
			for each (var module: Module in _modules ) {
				unregisterModule(module);			
			}
				
			_modules = null;
			_loaders = null;
		}
		
		public function scan() : void {
			var ldr : ModuleLoader;
			
			for (var i : int = 0; i < _loaders.length; i++) {
				ldr = _loaders[i] as ModuleLoader;
				unregisterLoader(ldr);
				
				ldr.dispose();				
				ldr = null;
				
				_loaders.splice( i, 1 );
				i--;
			}
			
			var module : Module;			
			var copy : Array = [].concat( _modules );
			
			for (i = 0; i < copy.length; i++) {
				module = copy[i] as Module;
				module.system.sff_internal::_scan();
				
				removeModule(module);
				
				module.sff_internal::_dispose( );
				module = null;
								
			}			
		}		
		
		//module loader handler
		protected function registerLoader(ldr: ModuleLoader ) : void {
			unregisterLoader(ldr);
			
			ldr.addEventListener( Event.COMPLETE , onLoaderComplete );
			ldr.addEventListener( ModuleEvent.LOADED , onModuleLoaded );
			ldr.addEventListener( ErrorEvent.ERROR , onModuleError );
		}

		protected function unregisterLoader(ldr: ModuleLoader ) : void {
			ldr.removeEventListener( Event.COMPLETE , onLoaderComplete );
			ldr.removeEventListener( ModuleEvent.LOADED , onModuleLoaded );
			ldr.removeEventListener( ErrorEvent.ERROR , onModuleError );
		}

		
		private function onModuleError(evt: ErrorEvent) : void {
			var ldr : ModuleLoader = evt.currentTarget as ModuleLoader;
			unregisterLoader(ldr);
		
			_loaders.splice(_loaders.indexOf(ldr), 1 );
		}
		
		private function onLoaderComplete(evt: Event) : void {
			var ldr: ModuleLoader = evt.currentTarget as ModuleLoader;
			unregisterLoader(ldr);
			
			_loaders.splice( _loaders.indexOf(ldr), 1 );
		}
		
		private function onModuleLoaded(evt : ModuleEvent) : void {
			//if( contains(event.module) ) throw new Error( "onLoaderComplete" );
			
			var module:Module = evt.module;
			_modules.push(module );
			
			registerModule(module );
			
			module.addEventListener( ModuleEvent.ADDED, onModuleAddHandler );
			
			
			module.dispatchEvent( new ModuleEvent( ModuleEvent.ADDED, module, true, false ) );
		}
		
		
		//module handler
		protected function registerModule(module : Module ) : void {
			module.addEventListener( ModuleEvent.ADDED, onModuleAddHandler );
			module.addEventListener( ModuleEvent.REMOVED, onModuleRemoveHandler );
		}

		protected function unregisterModule(module : Module ) : void {
			module.removeEventListener( ModuleEvent.ADDED, onModuleAddHandler );
			module.removeEventListener( ModuleEvent.REMOVED, onModuleRemoveHandler );
		}

		protected function onModuleAddHandler(evt : ModuleEvent) : void {
			dispatchEvent(evt);
		}

		protected function onModuleRemoveHandler(evt : ModuleEvent) : void {
			dispatchEvent(evt);
		}		
	}
}
